#include "mutgui.h"
#include <algorithm>
#include <vector>
#include <list>

struct SCREEN_VERTEX{
	float x,y,z,w;
	D3DCOLOR c;
	float u,v;
	static DWORD FVF;
};
DWORD SCREEN_VERTEX::FVF = D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1;

class CMUTDialog;
class CMUTControl{
public:
	TString title;
	DECL_GET_SET(CMUTDialog*,ParentDialog)
	DECL_GET_SET(DWORD,Style)
	DECL_GET_SET(int,x)
	DECL_GET_SET(int,y)
	DECL_GET_SET(int,Width)
	DECL_GET_SET(int,Height)
	DECL_GET_SET(bool,Visible)
	DECL_GET_SET(float,Alpha)
	DECL_GET_SET(DWORD,ID)
	DECL_GET_SET(MUTCTRL_TYPE,CtrlType)
	DECL_GET_SET(D3DXCOLOR,Color)
	DECL_GET_SET(D3DXCOLOR,TextColor)
	DECL_GET_SET(RECT,ImgRect)
	DECL_GET_SET(bool,RectShadow)
	DECL_GET_SET(bool,TextShadow);
	D3DXCOLOR GetColorMulAlpha(){
		D3DXCOLOR c(Color);
		c.a *= Alpha;
		return c;
	}
	D3DXCOLOR GetTextColorMulAlpha(){
		D3DXCOLOR c(TextColor);
		c.a *= Alpha;
		return c;
	}
	
	CMUTControl(){
		ZeroMemory(this,sizeof(CMUTControl));
		SetAlpha(0.0f);
		SetVisible(true);
		SetRect(&ImgRect,0,0,1,1);
		SetRectShadow(false);
		SetTextShadow(false);
		SetParentDialog(NULL);
	}
	virtual void SetText(LPWSTR ptr) {
		title = ptr;
	}
	virtual bool InRect(POINT pt);
	virtual void Render(LPDIRECT3DDEVICE9 pDevice){}
	virtual bool OnMouseMessage(POINT pt, UINT uMsg, WPARAM wParam, LPARAM lParam){ return false; }
	virtual bool OnKeyboardMessage(UINT uMsg, WPARAM wParam, LPARAM lParam){ return false; }
	virtual int HandleMessage(UINT Msg,WPARAM wParam,LPARAM lParam){ return 0; }
};

class CMUTStatic : public CMUTControl{
public:
	CMUTStatic();
	virtual void Render(LPDIRECT3DDEVICE9 pDevice);
};

class CMUTButton : public CMUTControl {
public:
	DECL_GET_SET(bool,Pressed)
	DECL_GET_SET(bool,Hover)
	DECL_GET_SET(bool,Convex)
	CMUTButton();
	virtual void Render(LPDIRECT3DDEVICE9 pDevice);
	virtual bool OnMouseMessage(POINT pt, UINT uMsg, WPARAM wParam, LPARAM lParam);
};

class CMUTCheckBox : public CMUTControl{
public:
	DECL_GET_SET(bool, Hover)
	DECL_GET_SET(bool, Pressed)
	DECL_GET_SET(bool, Check)
	CMUTCheckBox();
	virtual void Render(LPDIRECT3DDEVICE9 pDevice);
	virtual bool OnMouseMessage(POINT pt, UINT uMsg, WPARAM wParam, LPARAM lParam);
	virtual int HandleMessage(UINT Msg,WPARAM wParam,LPARAM lParam);
	bool InCheckRect(POINT pt);
};

class CMUTRadioButton : public CMUTControl{
public:
	DECL_GET_SET(bool, Hover)
	DECL_GET_SET(bool, Pressed)
	DECL_GET_SET(bool, Check)
	CMUTRadioButton();
	virtual void Render(LPDIRECT3DDEVICE9 pDevice);
	virtual bool OnMouseMessage(POINT pt, UINT uMsg, WPARAM wParam, LPARAM lParam);
	bool InRadioRect(POINT pt);
};

class CMUTScrollBar : public CMUTControl{
public:
	CMUTButton Btnup,Btndown,Btnbar,Btnslider;
	DECL_GET_SET(int,Pos)
	DECL_GET_SET(int,Range)
	DECL_GET_SET(int,RangeMax)
	DECL_GET_SET(int,RangePos)
	DECL_GET_SET(int,PageSize)
	DECL_GET_SET(float,PressTime)
	DECL_GET_SET(float,ScrollTime)
	DECL_GET_SET(int,dy)

	CMUTScrollBar();
	void CheckPos();
	void UpdateRangePos(int RangePos);
	void UpdatePos(int Pos);
	int Scroll(int delta);
	int PosToRangePos(int Pos);
	int RangePosToPos(int RangePos);
	virtual void Render(LPDIRECT3DDEVICE9 pDevice);
	virtual bool OnMouseMessage(POINT pt, UINT uMsg, WPARAM wParam, LPARAM lParam);
};

class CMUTListBox : public CMUTControl{
public:
	CMUTScrollBar scroll;
	list<TString> items;
	DECL_GET_SET(int, ItemSelected)
	DECL_GET_SET(int, ItemStart)
	DECL_GET_SET(bool, MovingEffect)
	DECL_GET_SET(bool, SelectedEffect)
	TString* GetString(int index);
	CMUTListBox();
	int GetSelectedByMouse(POINT pt);
	virtual void Render(LPDIRECT3DDEVICE9 pDevice);
	virtual bool OnMouseMessage(POINT pt, UINT uMsg, WPARAM wParam, LPARAM lParam);
	virtual int HandleMessage(UINT Msg,WPARAM wParam,LPARAM lParam);
};

class CMUTComboBox : public CMUTControl{
public:
	CMUTButton BtnText;
	CMUTButton BtnList;
	CMUTListBox List;
	CMUTComboBox();
	virtual bool InRect(POINT pt);
	virtual void Render(LPDIRECT3DDEVICE9 pDevice);
	virtual bool OnMouseMessage(POINT pt, UINT uMsg, WPARAM wParam, LPARAM lParam);
	virtual int HandleMessage(UINT Msg,WPARAM wParam,LPARAM lParam);
};

class CMUTSlider : public CMUTControl{
public:
	CMUTButton Btn;
	CMUTButton Bar;
	DECL_GET_SET(int, Range)
	DECL_GET_SET(int, Pos)
	DECL_GET_SET(float, TimeRecord)
	DECL_GET_SET(POINT, PointRecord)
	CMUTSlider();
	void CheckPos(){
		if (GetPos()>GetWidth())
			SetPos(GetWidth());
		else if(GetPos()<0)
			SetPos(0);
	}
	virtual void Render(LPDIRECT3DDEVICE9 pDevice);
	virtual bool OnMouseMessage(POINT pt, UINT uMsg, WPARAM wParam, LPARAM lParam);
	virtual int HandleMessage(UINT Msg,WPARAM wParam,LPARAM lParam);
};

class CMUTEditBox : public CMUTControl{
public:
	vector<WCHAR> str;
	vector<int> strx;
	vector<int> enters;
	vector<int> linechar;
	CMUTScrollBar scroll;
	DECL_GET_SET(int, UpDownX)
	DECL_GET_SET(bool, ShowScroll)
	DECL_GET_SET(int, StartLine)
	DECL_GET_SET(int, ShowLine)
	DECL_GET_SET(int, CaretPos)
	DECL_GET_SET(int, CaretPosStart)
	DECL_GET_SET(int, CaretPosEnd)
	DECL_GET_SET(float, TimeRecord)
	DECL_GET_SET(bool, CaretInShowLine)
	DECL_GET_SET(bool, ShowCaret)
	DECL_GET_SET(bool, Analyse)
	DECL_GET_SET(bool, Pressed)
	SCRIPT_STRING_ANALYSIS ssa;
	CMUTEditBox();
	void AnalyseString();
	int CPtoX(int cp);
	int XtoCP(int x);
	int Point2CP(POINT pt,BOOL CheckShow=TRUE);
	int MoveCaretUp(int bias);
	int MoveCaretDown(int bias);
	int MoveCaretLeft(int bias);
	int MoveCaretRight(int bias);
	void ResetCaret();
	void RemoveSelection();
	void CopyToClipboard();
	void PasteFromClipboard();
	void InsertString(int Start, WCHAR* str);
	virtual void Render(LPDIRECT3DDEVICE9 pDevice);
	virtual bool OnMouseMessage(POINT pt, UINT uMsg, WPARAM wParam, LPARAM lParam);
	virtual bool OnKeyboardMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
};

class CMUTDialog : public CMUTControl{
public:
	DECL_GET_SET(bool,Caption)
	DECL_GET_SET(MUTDLGPROC, DlgProc)
	CMUTButton Btncaption;
	list<MUTHWND> subcontrols;
	CMUTDialog();
	virtual void Render(LPDIRECT3DDEVICE9 pDevice);
	bool OnMsgProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
	void OnRelease();
};
void MUTGUIDrawRect(LPDIRECT3DDEVICE9 pDevice,int x,int y,int Width,int Height,D3DXCOLOR c,const RECT* pRtSrc=NULL,BOOL bShadow=FALSE,int dx=0,int dy=0,int sx=0,int sy=0);
int MUTGUIDrawText(LPWSTR str, int x,int y,int Width,int Height,DWORD format,D3DXCOLOR c,BOOL bShadow=FALSE);

bool CMUTControl::InRect(POINT pt){
	if (pt.x>=x && pt.y>=y && pt.x<=x+Width && pt.y<=y+Height)
		return true;
	return false;
}
float Lerp(float a,float b,float t){
	return a+(b-a)*t;
}

#define MGCOLOR_CHANGERATE 10
LPD3DXSPRITE g_pSprite=NULL;
LPDIRECT3DTEXTURE9 g_pTexture=NULL;
LPD3DXFONT g_pFont=NULL;

CMUTDialog* g_pFocusDialog=NULL;
CMUTControl* g_pFocusControl=NULL;

#define MGDIALOGCOLOR_FOCUSCAPTION D3DXCOLOR(0,0,0.5,1)
#define MGDIALOGCOLOR_FOCUSTEXT D3DXCOLOR(0,0,0,1)
#define MGDIALOGCOLOR_NORMALCAPTION D3DXCOLOR(0.5,0.5,0.5,1)
#define MGDIALOGCOLOR_NORMALTEXT D3DXCOLOR(1,1,1,1)
#define MGDIALOGCOLOR_BKG D3DXCOLOR(0.9,0.9,0.9,0.95)
#define MGDIALOG_CAPTIONSIZE 15
CMUTDialog::CMUTDialog(){
	SetColor(MGDIALOGCOLOR_NORMALCAPTION);
	SetTextColor(MGDIALOGCOLOR_NORMALTEXT);
	SetVisible(true);
	SetAlpha(0);
}
void CMUTDialog::Render(LPDIRECT3DDEVICE9 pDevice){
	float fStep = MUTState()->GetElapsedTime();
	if (GetVisible()){
		SetAlpha(GetAlpha()+fStep);
		if (GetAlpha()>1.0f)
			SetAlpha(1.0f);
	}

	if (GetCaption()){
		D3DXCOLOR bk = MGDIALOGCOLOR_BKG;
		bk.a *= GetAlpha();
		MUTGUIDrawRect(pDevice,
			x,y,Width,Height,bk);
		Btncaption.Setx(x);
		Btncaption.Sety(y);
		Btncaption.SetWidth(Width);
		Btncaption.SetHeight(MGDIALOG_CAPTIONSIZE);
		if (g_pFocusDialog == this){
			SetColor(MGDIALOGCOLOR_FOCUSCAPTION);
			SetTextColor(MGDIALOGCOLOR_FOCUSTEXT);
		}else{
			SetColor(MGDIALOGCOLOR_NORMALCAPTION);
			SetTextColor(MGDIALOGCOLOR_NORMALTEXT);
		}
		MUTGUIDrawRect(pDevice,
			x,y,Width,MGDIALOG_CAPTIONSIZE,GetColorMulAlpha());
	}
	for (auto itr = subcontrols.begin(); 
			itr != subcontrols.end(); itr ++){
		CMUTControl* pControl = (CMUTControl*)(*itr);
		pControl->SetAlpha(GetAlpha());
		if (pControl == g_pFocusControl) continue;
		if (pControl->GetVisible()){
			pControl->Render(pDevice);
		}
	}
	if (g_pFocusControl)
		g_pFocusControl->Render(pDevice);
}
void CMUTDialog::OnRelease(){
	for (auto itr = subcontrols.begin();
			itr != subcontrols.end(); itr++){
		CMUTControl* pControl = (CMUTControl*)*itr;
		if (pControl)
			delete pControl;
		*itr = NULL;
	}subcontrols.empty();
}

#define MGCOLOR_WHITE D3DXCOLOR(1,1,1,1)
#define MGCOLOR_GRAY D3DXCOLOR(0.8,0.8,0.8,1)
#define MGCOLOR_BLACK D3DXCOLOR(0,0,0,1)
#define MGCOLOR_BLUE D3DXCOLOR(0,0,1,1)
#define MGCOLOR_LIGHT D3DXCOLOR(0.9,0.9,0.9,1)
#define MGCOLOR_DARK D3DXCOLOR(0.2,0.2,0.2,1)

void MUTGUIDrawRect(LPDIRECT3DDEVICE9 pDevice,int x,int y,int Width,int Height,D3DXCOLOR c,const RECT* pRtSrc,BOOL bShadow,int dx,int dy,int sx,int sy){
	if (c.a<=0) return;
	D3DXMATRIX matScale,matTrans;
	RECT rtSrc;
	SetRect(&rtSrc,0,0,1,1);
	if (pRtSrc) rtSrc = *pRtSrc;
	
	if (bShadow){
		D3DXMatrixTranslation(&matTrans,x+dx,y+dy,0);
		D3DXMatrixScaling(&matScale,(Width+sx) / float(rtSrc.right-rtSrc.left),(Height+sy) / float(rtSrc.bottom-rtSrc.top),0);
		D3DXCOLOR framecolor = MGCOLOR_DARK;
		framecolor.a = c.a;
		g_pSprite->SetTransform(&(matScale*matTrans));
		g_pSprite->Draw(g_pTexture,&rtSrc,NULL,NULL,framecolor);
	}
	D3DXMatrixTranslation(&matTrans,x,y,0);
	D3DXMatrixScaling(&matScale,Width / float(rtSrc.right-rtSrc.left),Height / float(rtSrc.bottom-rtSrc.top),0);
	
	g_pSprite->SetTransform(&(matScale*matTrans));
	g_pSprite->Draw(g_pTexture,&rtSrc,NULL,NULL,c);
}

int MUTGUIDrawText(LPWSTR str, int x,int y,int Width,int Height,DWORD format,D3DXCOLOR c,BOOL bShadow){
	if (lstrlen(str)>0){
		D3DXMATRIX matIdentity;
		RECT rt;
		SetRect(&rt,x,y,x+Width,y+Height);
		D3DXMatrixIdentity(&matIdentity);
		g_pSprite->SetTransform(&matIdentity);
		if (bShadow){
			rt.left++; rt.top++;
			rt.right++; rt.bottom++;
			D3DXCOLOR shadow = MGCOLOR_BLACK;
			shadow.a = c.a;
			g_pFont->DrawTextW(g_pSprite,str,-1,&rt,format,shadow);
			rt.left--; rt.top--;
			rt.right--; rt.bottom--;
		}
		return g_pFont->DrawTextW(g_pSprite,str,-1,&rt,format,c);
	}
	return 0;
}

CMUTStatic::CMUTStatic(){
	SetTextColor(MGCOLOR_BLACK);
}

void CMUTStatic::Render(LPDIRECT3DDEVICE9 pDevice){
	DWORD fmt = DT_LEFT;
	if (Style&SS_CENTER)
		fmt = DT_CENTER|DT_VCENTER;
	else if (Style&SS_RIGHT)
		fmt = DT_RIGHT;
	MUTGUIDrawText(title,
		x,y,
		Width,Height,
		fmt,GetTextColorMulAlpha());
}

const RECT MGRECT_BUTTON = {96,196,256,236};
#define MGBTNCOLOR_NORMAL D3DXCOLOR(1,1,1,1)
#define MGBTNCOLOR_HOVER D3DXCOLOR(0.75,0.85,1,1)
#define MGBTNCOLOR_PRESSED MGBTNCOLOR_NORMAL
#define MGBTNTEXT_NORMAL D3DXCOLOR(0,0,0,1)
#define MGBTNTEXT_HOVER MGCOLOR_BLACK
#define MGBTNTEXT_PRESSED MGCOLOR_BLACK
CMUTButton::CMUTButton(){
	//SetColor(MGBTNCOLOR_NORMAL);
	//SetTextColor(MGBTNTEXT_NORMAL);
	SetColor(MGCOLOR_BLUE);
	SetTextColor(MGCOLOR_BLACK);
	SetHover(false);
	SetPressed(false);
	SetConvex(true);
	SetRectShadow(true);
	SetImgRect(MGRECT_BUTTON);
}
void CMUTButton::Render(LPDIRECT3DDEVICE9 pDevice){
	float fLerp = MUTState()->GetElapsedTime()*MGCOLOR_CHANGERATE;
	int dx=0, dy=0;
	D3DXCOLOR color;
	if (GetPressed()){
		SetColor(MGBTNCOLOR_PRESSED);
		SetTextColor(MGBTNTEXT_PRESSED);
	}else if(GetHover()){
		D3DXColorLerp(&color,&GetColor(),&MGBTNCOLOR_HOVER,fLerp);
		SetColor(color);
		D3DXColorLerp(&color,&GetTextColor(),&MGBTNTEXT_HOVER,fLerp);
		SetTextColor(color);
	}else{
		D3DXColorLerp(&color,&GetColor(),&MGBTNCOLOR_NORMAL,fLerp);
		SetColor(color);
		D3DXColorLerp(&color,&GetTextColor(),&MGBTNTEXT_NORMAL,fLerp);
		SetTextColor(color);
	}	
	int sx = 2, sy= 2;
	if (GetPressed()&&GetRectShadow()){
		dx = dy = 2;
		sx = sy = 0;
	}
	MUTGUIDrawRect(pDevice,x+dx,y+dy,Width,Height,GetColorMulAlpha(),&ImgRect,RectShadow,-1,-1,2,2);

	MUTGUIDrawText(title,
		x+dx,y+dy,
		Width,Height,
		DT_CENTER|DT_VCENTER,GetTextColorMulAlpha());
}
bool CMUTButton::OnMouseMessage(POINT pt, UINT uMsg, WPARAM wParam, LPARAM lParam){
	if (InRect(pt)){
		switch (uMsg){
		case WM_LBUTTONDBLCLK:
		case WM_LBUTTONDOWN:
			SetPressed(true);
			break;
		case WM_LBUTTONUP:
			if (GetPressed()){
				//Click_Message
			}
			SetPressed(false);
			break;
		case WM_MOUSEMOVE:
			if (!(wParam&MK_LBUTTON)){ // Mouse_Up
				if (GetPressed()){
					//click
				}
				SetPressed(false);
			}
			SetHover(true);
			break;
		}
	}else{
		SetHover(false);	
		switch (uMsg){
		case WM_LBUTTONUP:
			SetPressed(false);
			break;
		case WM_MOUSEMOVE:
			if (!(wParam&MK_LBUTTON)){
				SetPressed(false);
			}
			break;
		}
	}
	return false;
}

const RECT MGRECT_UNCHECKED = {236,236,256,256};
const RECT MGRECT_CHECKED = {216,236,236,256};
#define MG_CHECKBOXSIZE 20
#define MG_CHECKBOXINTERVAL 4
#define MGCHKCOLOR_HOVER D3DXCOLOR(1,1,1,0.8)
#define MGCHKCOLOR_NORMAL D3DXCOLOR(1,1,1,0.5)
CMUTCheckBox::CMUTCheckBox(){
	SetTextColor(MGCOLOR_WHITE);
	SetCheck(false);
	SetHover(false);
	SetPressed(false);
	ImgRect = MGRECT_UNCHECKED;
}
void CMUTCheckBox::Render(LPDIRECT3DDEVICE9 pDevice){
	RECT rt = ImgRect;
	if (GetCheck()){
		int d = rt.right-rt.left;
		rt.left -= d;
		rt.right -= d;
	}

	float fLerp = MUTState()->GetElapsedTime() * MGCOLOR_CHANGERATE;
	D3DXCOLOR color;
	if (GetHover()){
		D3DXColorLerp(&color,&GetColor(),&MGCHKCOLOR_HOVER,fLerp);
		SetColor(color);
	}else{
		D3DXColorLerp(&color,&GetColor(),&MGCHKCOLOR_NORMAL,fLerp);
		SetColor(color);
	}

	MUTGUIDrawRect(pDevice,
		x,y,
		MG_CHECKBOXSIZE,MG_CHECKBOXSIZE,
		GetColorMulAlpha(),&rt);

	MUTGUIDrawText(title,
		x+MG_CHECKBOXSIZE+MG_CHECKBOXINTERVAL,y,
		Width-MG_CHECKBOXSIZE-MG_CHECKBOXINTERVAL,MG_CHECKBOXSIZE,
		DT_LEFT|DT_VCENTER,GetTextColorMulAlpha(),TRUE);
}
bool CMUTCheckBox::OnMouseMessage(POINT pt, UINT uMsg, WPARAM wParam, LPARAM lParam){
	if (InCheckRect(pt)){
		switch (uMsg){
		case WM_LBUTTONDOWN:
			SetPressed(true);
			break;
		case WM_LBUTTONUP:
			if (GetPressed()){
				SetCheck(!GetCheck());
			}
			SetPressed(false);
			break;
		case WM_MOUSEMOVE:
			SetHover(true);
			break;
		}
	}else{
		SetHover(false);
		switch (uMsg){
		case WM_LBUTTONUP:
			SetPressed(false);
			break;
		}
	}
	return false;
}
int CMUTCheckBox::HandleMessage(UINT Msg,WPARAM wParam,LPARAM lParam){
	switch (Msg){
	case BM_GETCHECK:
		if (GetCheck())
			return BST_CHECKED;
		else
			return BST_UNCHECKED;
		break;
	}
	return 0;
}
bool CMUTCheckBox::InCheckRect(POINT pt){
	if (pt.x>=x && pt.y>=y && pt.x<=x+MG_CHECKBOXSIZE && pt.y<=y+MG_CHECKBOXSIZE)
		return true;
	return false;
}

const RECT MGRECT_RADIOUNCHECKED = {196,236,216,256};
const RECT MGRECT_RADIOCHECKED = {176,236,196,256};
#define MG_RADIOBUTTONSIZE MG_CHECKBOXSIZE
#define MG_RADIOBUTTONINTERVAL MG_CHECKBOXINTERVAL
#define MGRADIOCOLOR_HOVER MGCHKCOLOR_HOVER
#define MGRADIOCOLOR_NORMAL MGCHKCOLOR_NORMAL
CMUTRadioButton::CMUTRadioButton(){
	SetTextColor(MGCOLOR_WHITE);
	SetCheck(false);
	SetHover(false);
	SetPressed(false);
	ImgRect = MGRECT_RADIOUNCHECKED;
}
void CMUTRadioButton::Render(LPDIRECT3DDEVICE9 pDevice){
	RECT rt = ImgRect;
	if (GetCheck()){
		int d = rt.right - rt.left;
		rt.left -= d;
		rt.right -= d;
	}

	float fLerp = MUTState()->GetElapsedTime() * MGCOLOR_CHANGERATE;
	D3DXCOLOR color;
	if (GetHover()){
		D3DXColorLerp(&color,&GetColor(),&MGRADIOCOLOR_HOVER,fLerp);
		SetColor(color);
	}else{
		D3DXColorLerp(&color,&GetColor(),&MGRADIOCOLOR_NORMAL,fLerp);
		SetColor(color);
	}

	MUTGUIDrawRect(pDevice,
		x,y,
		MG_RADIOBUTTONSIZE,MG_RADIOBUTTONSIZE,
		GetColorMulAlpha(),&rt);

	MUTGUIDrawText(/*title*/L"RadioButton",
		x+MG_RADIOBUTTONSIZE+MG_RADIOBUTTONINTERVAL,y,
		Width-MG_RADIOBUTTONSIZE-MG_RADIOBUTTONINTERVAL,MG_RADIOBUTTONSIZE,
		DT_LEFT|DT_VCENTER,GetTextColorMulAlpha(),TRUE);
}
bool CMUTRadioButton::InRadioRect(POINT pt){
	if (pt.x>=x && pt.y>=y && pt.x<=x+MG_RADIOBUTTONSIZE && pt.y<=y+MG_RADIOBUTTONSIZE)
		return true;
	return false;
}
bool CMUTRadioButton::OnMouseMessage(POINT pt, UINT uMsg, WPARAM wParam, LPARAM lParam){
	if (InRadioRect(pt)){
		switch (uMsg){
		case WM_LBUTTONDOWN:
			SetPressed(true);
			break;
		case WM_LBUTTONUP:
			if (GetPressed()){
				SetCheck(!GetCheck());
			}
			SetPressed(false);
			break;
		case WM_MOUSEMOVE:
			SetHover(true);
			break;
		}
	}else{
		SetHover(false);
		switch (uMsg){
		case WM_LBUTTONUP:
			SetPressed(false);
			break;
		}
	}
	return false;
}

#define MG_SCROLLBARSIZE 15
const RECT MGRECT_SCROLLUP = {136,236,156,256};
const RECT MGRECT_SCROLLDOWN = {116,236,136,256};
const RECT MGRECT_SCROLLSLIDER = {216,36,256,196};
CMUTScrollBar::CMUTScrollBar(){
	Btnup.SetColor(MGCOLOR_WHITE);
	Btndown.SetColor(MGCOLOR_WHITE);
	Btnbar.SetColor(MGCOLOR_WHITE);
	Btnslider.SetColor(D3DXCOLOR(0.4,0.6,1,1));
	Btnslider.SetImgRect(MGRECT_SCROLLSLIDER);

	Btnup.SetWidth(MG_SCROLLBARSIZE);
	Btnup.SetHeight(MG_SCROLLBARSIZE);
	Btndown.SetWidth(MG_SCROLLBARSIZE);
	Btndown.SetHeight(MG_SCROLLBARSIZE);
	Btnbar.SetWidth(MG_SCROLLBARSIZE);
	SetRange(0);
	SetRangeMax(100);
	SetRangePos(0);
	SetPageSize(1);
	SetPos(0);
	Btnslider.SetWidth(MG_SCROLLBARSIZE);
	Btnslider.SetHeight(MG_SCROLLBARSIZE);

	Btnup.SetImgRect(MGRECT_SCROLLUP);
	Btndown.SetImgRect(MGRECT_SCROLLDOWN);

	Btnup.SetRectShadow(false);
	Btndown.SetRectShadow(false);
}

#define MGSCR_PRESSTIME 0.5f
#define MGSCR_SCROLLTIME 0.1f
void CMUTScrollBar::Render(LPDIRECT3DDEVICE9 pDevice){
	Btnup.SetAlpha(GetAlpha());
	Btndown.SetAlpha(GetAlpha());
	Btnbar.SetAlpha(GetAlpha());
	Btnslider.SetAlpha(GetAlpha());

	Btnup.Setx(x);
	Btnup.Sety(y);

	Btnbar.Setx(x);
	Btnbar.Sety(y+MG_SCROLLBARSIZE);
	Btnbar.SetHeight(Height-MG_SCROLLBARSIZE*2);

	Btndown.Setx(x);
	Btndown.Sety(y+Height-MG_SCROLLBARSIZE);


	/*
	MUTGUIDrawRect(pDevice,
		Btnup.Getx(),Btnup.Gety(),
		Btnup.GetWidth(),Btnup.GetHeight(),
		Btnup.GetColorMulAlpha(),&MGRECT_SCROLLUP);*/
	Btnup.Render(pDevice);
	MUTGUIDrawRect(pDevice,
		Btndown.Getx(),Btndown.Gety(),
		Btndown.GetWidth(),Btndown.GetHeight(),
		Btndown.GetColorMulAlpha(),&MGRECT_SCROLLDOWN);
	Btndown.Render(pDevice);
	/*MUTGUIDrawRect(pDevice,
		Btnbar.Getx(),Btnbar.Gety(),
		Btnbar.GetWidth(),Btnbar.GetHeight(),
		Btnbar.GetColorMulAlpha());*/

	if (Btnup.GetPressed()||Btndown.GetPressed()){
		SetPressTime(GetPressTime()+MUTState()->GetElapsedTime());
		if (GetPressTime()>MGSCR_PRESSTIME){
			SetScrollTime(GetScrollTime()+MUTState()->GetElapsedTime());
			if (GetScrollTime()>MGSCR_SCROLLTIME){
				UpdateRangePos( GetRangePos()+Getdy() );
				SetScrollTime(0.0f);
			}
		}
	}
	if (Btnbar.GetPressed()){
		SetPressTime(GetPressTime()+MUTState()->GetElapsedTime());
		if (GetPressTime()>MGSCR_PRESSTIME){
			POINT pt = MUTState()->GetMousePos();
			if ( (Getdy()>0&&pt.y>Btnslider.Gety()+Btnslider.GetHeight()) ||
				 (Getdy()<0&&pt.y<Btnslider.Gety()) ){
				SetScrollTime(GetScrollTime()+MUTState()->GetElapsedTime());
				if (GetScrollTime()>MGSCR_SCROLLTIME){
					UpdateRangePos( GetRangePos()+Getdy() );
					SetScrollTime(0.0f);
				}
			}
		}
	}

	if (GetRange()){

		//y = he^(-bx), b=log(h/10)/t, y = he^(-log(h/10)*x/t)
		int h = Btnbar.GetHeight()-MG_SCROLLBARSIZE;
		int sliderh = h*exp(-log(h/10.0)*GetRange()/GetRangeMax());
		if (sliderh<10) sliderh=10;
		Btnslider.SetHeight(sliderh);
		if (!Btnslider.GetPressed()){
			SetPos( RangePosToPos(GetRangePos()));
		}
		Btnslider.Setx(x);
		Btnslider.Sety(Btnbar.Gety()+GetPos());
		//Btnslider.Render(pDevice);
	
		MUTGUIDrawRect(pDevice,
			Btnslider.Getx(),Btnslider.Gety(),
			Btnslider.GetWidth(),Btnslider.GetHeight(),
			Btnslider.GetColorMulAlpha(),&Btnslider.GetImgRect(),FALSE);
	}
}
int CMUTScrollBar::PosToRangePos(int Pos){
	int iHeight = Btnbar.GetHeight() - Btnslider.GetHeight();
	return float(Pos) / iHeight * GetRange();
}
int CMUTScrollBar::RangePosToPos(int RangePos){
	int iHeight = Btnbar.GetHeight() - Btnslider.GetHeight();
	return float(RangePos)/Range*iHeight;
}
void CMUTScrollBar::UpdateRangePos(int RangePos){
	SetRangePos( RangePos );
	SetPos( RangePosToPos(RangePos) );
	CheckPos();
}
void CMUTScrollBar::UpdatePos(int Pos){
	SetPos( Pos );
	SetRangePos( PosToRangePos(Pos) );
	CheckPos();
}
void CMUTScrollBar::CheckPos(){
	if (Pos<0) 
		Pos=0;
	if (Pos>Btnbar.GetHeight()-Btnslider.GetHeight())
		Pos=Btnbar.GetHeight()-Btnslider.GetHeight();
	if (RangePos<0)
		RangePos=0;
	if (RangePos>Range)
		RangePos=Range;
}
bool CMUTScrollBar::OnMouseMessage(POINT pt, UINT uMsg, WPARAM wParam, LPARAM lParam){
	Btnup.OnMouseMessage(pt,uMsg,wParam,lParam);
	Btnbar.OnMouseMessage(pt,uMsg,wParam,lParam);
	Btndown.OnMouseMessage(pt,uMsg,wParam,lParam);
	if (GetRange())
		Btnslider.OnMouseMessage(pt,uMsg,wParam,lParam);
	switch (uMsg){
	case WM_LBUTTONDOWN:
	case WM_LBUTTONDBLCLK:
		if (Btnup.GetPressed()){
			UpdateRangePos( GetRangePos()-1 );
			Setdy(-1);
		}else if (Btndown.GetPressed()){
			UpdateRangePos( GetRangePos()+1 );
			Setdy(1);
		}else if (Btnbar.GetPressed()&&!Btnslider.GetPressed()){
			if (pt.y>Btnslider.Gety()){
				UpdateRangePos( GetRangePos()+GetPageSize() );
				Setdy(GetPageSize());
			}else if (pt.y<Btnslider.Gety()){
				UpdateRangePos( GetRangePos()-GetPageSize() );
				Setdy(-GetPageSize());
			}
		}
		SetPressTime(0.0f);
		SetScrollTime(0.0f);
		break;
	case WM_MOUSEMOVE:
		if (Btnslider.GetPressed()){
			POINT prept = MUTState()->GetPreMousePos();
			int dy = pt.y-prept.y;
			if ( (dy<0&&pt.y<Btnslider.Gety()+Btnslider.GetHeight()) ||
				(dy>0&&pt.y>Btnslider.Gety())){
				UpdatePos(GetPos()+dy);
			}
		}
		break;
	}
	return false;
}
int CMUTScrollBar::Scroll(int delta){
	//int delta = GET_WHEEL_DELTA_WPARAM(wParam)/WHEEL_DELTA;
	RangePos -= delta;
	if (RangePos<0) RangePos = 0;
	else if (RangePos>Range) RangePos = Range;
	return RangePos;
}

#define MG_LISTITEMHEIGHT 18
#define MG_LISTPADDING 3
#define MGLBCOLOR_BACKGROUND D3DXCOLOR(1,1,1,1)
#define MGLBCOLOR_ITEMBKSELECTED D3DXCOLOR(0.4,0.6,1,1)
#define MGLBCOLOR_ITEMTEXTSELECTED D3DXCOLOR(1,1,1,1)
#define MGLBCOLOR_ITEMBKNORMAL D3DXCOLOR(0,0,0,0)
#define MGLBCOLOR_ITEMTEXTNORMAL D3DXCOLOR(0,0,0,1)
CMUTListBox::CMUTListBox(){
	SetItemSelected(-1);	
	SetItemStart(0);
	SetColor(MGLBCOLOR_BACKGROUND);
	SetMovingEffect(false);
	SetSelectedEffect(true);
}
void CMUTListBox::Render(LPDIRECT3DDEVICE9 pDevice){
	MUTGUIDrawRect(pDevice,
		x,y,
		Width,Height,
		GetColorMulAlpha(),NULL,TRUE,-1,-1,2,2);
	int iY = y+MG_LISTPADDING;
	int iX = x+MG_LISTPADDING;
	int iWidth = Width - 2*MG_LISTPADDING;
	int iYmax = y+Height-MG_LISTITEMHEIGHT-MG_LISTPADDING;
	int cnt = 0;
	D3DXCOLOR cTextSelected = MGLBCOLOR_ITEMTEXTSELECTED;
	D3DXCOLOR cBkSelected = MGLBCOLOR_ITEMBKSELECTED;
	D3DXCOLOR cTextNormal = MGLBCOLOR_ITEMTEXTNORMAL;
	D3DXCOLOR cBkNormal = MGLBCOLOR_ITEMBKNORMAL;
	cTextSelected.a *= GetAlpha();
	cBkSelected.a *= GetAlpha();
	cTextNormal.a *= GetAlpha();
	cBkNormal.a *= GetAlpha();

	int iMovingSelected = -1;
	if (GetMovingEffect() && GetParentDialog() == g_pFocusDialog){
		iMovingSelected = GetSelectedByMouse(MUTState()->GetMousePos());
	}

	for (auto itr = items.begin(); 
			itr != items.end() && iY<=iYmax; itr++){
		if (cnt>=ItemStart){
			
			if ((GetSelectedEffect()&&cnt==GetItemSelected())||cnt==iMovingSelected){
				MUTGUIDrawRect(pDevice,iX,iY,iWidth-scroll.GetWidth(),MG_LISTITEMHEIGHT,cBkSelected);
				MUTGUIDrawText(*itr,iX+MG_LISTPADDING,iY,iWidth-2*MG_LISTPADDING-scroll.GetWidth(),MG_LISTITEMHEIGHT,DT_LEFT|DT_VCENTER,cTextSelected);
			}else{
				MUTGUIDrawText(*itr,iX+MG_LISTPADDING,iY,iWidth-2*MG_LISTPADDING-scroll.GetWidth(),MG_LISTITEMHEIGHT,DT_LEFT|DT_VCENTER,cTextNormal);
			}
			iY+=MG_LISTITEMHEIGHT;
		}
		cnt++;
	}

	//scrollbar
	int itemshow = cnt-ItemStart;

	scroll.SetRange(items.size()-itemshow);
	scroll.SetPageSize(itemshow-1);
	scroll.SetAlpha(GetAlpha());
	scroll.Setx(Getx()+GetWidth()-MG_SCROLLBARSIZE);
	scroll.Sety(Gety());
	scroll.SetHeight(GetHeight());
	scroll.SetWidth(MG_SCROLLBARSIZE);
	scroll.Render(pDevice);
	SetItemStart(scroll.GetRangePos());
}
TString* CMUTListBox::GetString(int index){
	if (index<0||index>=items.size()) return NULL;
	auto itr = items.begin();
	while (itr != items.end()){
		if (index == 0)
			return &(*itr);
		index--;
		itr++;
	}
	return NULL;
}
int CMUTListBox::GetSelectedByMouse(POINT pt){
	int iX = x+MG_LISTPADDING;
	int iY = y+MG_LISTPADDING;
	int iWidth = Width-MG_LISTPADDING*2;
	int iHeight = Height - MG_LISTPADDING*2;
	iHeight -= iHeight%MG_LISTITEMHEIGHT;
	if (pt.y-iY<0 || pt.y>iY+iHeight || pt.x<iX || pt.x>iX+iWidth)
		return -1;
	int iSelected = (pt.y-iY)/MG_LISTITEMHEIGHT+GetItemStart();
	if (iSelected>=items.size())
		return -1;
	return iSelected;
}
bool CMUTListBox::OnMouseMessage(POINT pt, UINT uMsg, WPARAM wParam, LPARAM lParam){
	scroll.OnMouseMessage(pt,uMsg,wParam,lParam);
	if (InRect(pt)){
		if (uMsg==WM_MOUSEWHEEL){
			SetItemStart( scroll.Scroll(GET_WHEEL_DELTA_WPARAM(wParam)/WHEEL_DELTA) );
		}
		if (!scroll.InRect(pt)){
			switch (uMsg){
			case WM_LBUTTONDOWN:
				{
					int iSelected = GetSelectedByMouse(pt);
					if (iSelected!=-1)
						SetItemSelected(iSelected);
					break;
				}
			}
		}
	}
	return false;
}
int CMUTListBox::HandleMessage(UINT Msg,WPARAM wParam,LPARAM lParam){
	switch (Msg){
	case LB_ADDSTRING:
		items.push_back(TString((LPWSTR)lParam));
		break;
	case LB_GETCURSEL:
		return GetItemSelected();
	case LB_GETTEXTLEN:
		{
			TString* pstr = GetString(wParam);
			if (!pstr){
				return LB_ERR;
			}
			return pstr->Length();
		}
	case LB_GETTEXT:
		{
			TString* pstr = GetString(wParam);
			if (!pstr){
				return LB_ERR;
			}
			lstrcpy((LPWSTR)lParam,*pstr);
			return pstr->Length();
		}
		break;
	}
	return 0;
}
int MUTGUISendMessage(MUTHWND hwnd,UINT Msg,WPARAM wParam,LPARAM lParam){
	CMUTControl* pControl = (CMUTControl*)hwnd;
	switch (pControl->GetCtrlType()){
	case MUTCTRL_BUTTON:
	case MUTCTRL_CHECKBOX:
	case MUTCTRL_RADIOBUTTON:
	case MUTCTRL_LISTBOX:
	case MUTCTRL_COMBOBOX:
	case MUTCTRL_SLIDER:
	case MUTCTRL_EDITBOX:
		return pControl->HandleMessage(Msg,wParam,lParam);
	}
	return 0;
}
BOOL MUTGUISetWindowText(MUTHWND hwnd,LPWSTR text){
	CMUTControl* pControl = (CMUTControl*)hwnd;
	if (pControl && text){
		pControl->SetText(text);
		return TRUE;
	}
	return FALSE;
}

#define MG_COMBOBOXSIZE 20
const RECT MGRECT_COMBOBTN = {156,236,176,256};
CMUTComboBox::CMUTComboBox(){
	List.SetVisible(false);
	BtnText.SetColor(MGCOLOR_WHITE);
	BtnText.SetTextColor(MGCOLOR_BLACK);
}
bool CMUTComboBox::InRect(POINT pt){
	return (pt.x>=x&&pt.y>=y&&pt.x<=x+Width&&pt.y<=y+MG_COMBOBOXSIZE);
}
void CMUTComboBox::Render(LPDIRECT3DDEVICE9 pDevice){
	
	BtnText.Setx(Getx());
	BtnText.Sety(Gety());
	BtnText.SetWidth(GetWidth()-MG_COMBOBOXSIZE);
	BtnText.SetHeight(MG_COMBOBOXSIZE);
	BtnList.Setx(Getx()+BtnText.GetWidth());
	BtnList.Sety(Gety());
	BtnList.SetWidth(MG_COMBOBOXSIZE);
	BtnList.SetHeight(MG_COMBOBOXSIZE);

	float fLerp = MUTState()->GetElapsedTime()*MGCOLOR_CHANGERATE;
	D3DXCOLOR color;
	int bx=0,by=0;
	if (BtnList.GetPressed()||BtnText.GetPressed()){
		BtnList.SetColor(MGBTNCOLOR_PRESSED);
	}else if (BtnList.GetHover()||BtnText.GetHover()||List.GetVisible()){
		D3DXColorLerp(&color,&BtnList.GetColor(),&MGBTNCOLOR_HOVER,fLerp);
		BtnList.SetColor(color);/*
		D3DXColorLerp(&color,&BtnText.GetColor(),&MGBTNCOLOR_HOVER,fLerp);
		BtnText.SetColor(color);
		D3DXColorLerp(&color,&BtnText.GetTextColor(),&MGBTNTEXT_HOVER,fLerp);
		BtnText.SetTextColor(color);*/
		bx = by = -1;
	}else{
		D3DXColorLerp(&color,&BtnList.GetColor(),&MGBTNCOLOR_NORMAL,fLerp);
		BtnList.SetColor(color);/*
		D3DXColorLerp(&color,&BtnText.GetColor(),&MGBTNCOLOR_NORMAL,fLerp);
		BtnText.SetColor(color);
		D3DXColorLerp(&color,&BtnText.GetTextColor(),&MGBTNTEXT_NORMAL,fLerp);
		BtnText.SetTextColor(color);*/
	}
	
	BtnText.SetAlpha(GetAlpha());
	BtnList.SetAlpha(GetAlpha());
	MUTGUIDrawRect(pDevice,
		BtnText.Getx(),BtnText.Gety(),
		BtnText.GetWidth(),BtnText.GetHeight(),
		BtnText.GetColorMulAlpha(),NULL,TRUE,-1,-1,1,1);
	MUTGUIDrawRect(pDevice,
		BtnList.Getx()+bx,BtnList.Gety()+by,
		BtnList.GetWidth(),BtnList.GetHeight(),
		BtnList.GetColorMulAlpha(),&MGRECT_COMBOBTN);
	
	List.Setx(Getx());
	List.Sety(Gety()+MG_COMBOBOXSIZE);
	List.SetWidth(BtnText.GetWidth());
	List.SetHeight(GetHeight()-MG_COMBOBOXSIZE);
	List.SetMovingEffect(true);
	List.SetSelectedEffect(false);
	List.SetParentDialog(GetParentDialog());
	if (List.GetVisible()){
		if (g_pFocusControl==this){
			List.SetAlpha( Lerp(List.GetAlpha(),1.0f,fLerp) );
			if (List.GetAlpha()>1.0f)
				List.SetAlpha(1.0f);
			List.Render(pDevice);
		}else
			List.SetVisible(false);
	}

	static WCHAR text[1024];
	int iSelected = -1;
	if ((iSelected = List.HandleMessage(LB_GETCURSEL,0,0))!=-1){
		if (1024>List.HandleMessage(LB_GETTEXTLEN,iSelected,0)){
			List.HandleMessage(LB_GETTEXT,iSelected,(LPARAM)text);
			MUTGUIDrawText(text,
				BtnText.Getx()+MG_LISTPADDING,BtnText.Gety(),
				BtnText.GetWidth()-2*MG_LISTPADDING,BtnText.GetHeight(),
				DT_LEFT|DT_VCENTER,BtnText.GetTextColorMulAlpha());
		}
	}
}
bool CMUTComboBox::OnMouseMessage(POINT pt, UINT uMsg, WPARAM wParam, LPARAM lParam){
	BtnList.OnMouseMessage(pt,uMsg,wParam,lParam);
	BtnText.OnMouseMessage(pt,uMsg,wParam,lParam);
	if (List.GetVisible()){
		int iSel = List.GetItemSelected();
		List.SetItemSelected(-1);
		List.OnMouseMessage(pt,uMsg,wParam,lParam);
		int iSel2 = List.GetItemSelected();
		if (iSel2 != -1){
			List.SetVisible(false);
			List.SetAlpha(0);
			return true;
		}else{
			List.SetItemSelected(iSel);
		}
		if (List.InRect(pt)){
			switch (uMsg){
			case WM_LBUTTONDBLCLK:
			case WM_LBUTTONDOWN:
				return true;
			}
		}
	}
	switch (uMsg){
	case WM_LBUTTONDBLCLK:
	case WM_LBUTTONDOWN:
		if (BtnList.GetPressed()||BtnText.GetPressed()){
			List.SetVisible(!List.GetVisible());
			if (!List.GetVisible()){
				List.SetAlpha(0);
			}
		}
		break;
	}
	return false;
}
int CMUTComboBox::HandleMessage(UINT Msg,WPARAM wParam,LPARAM lParam){
	switch (Msg){
	case CB_ADDSTRING:
		List.HandleMessage(LB_ADDSTRING,wParam,lParam);
		break;
	}
	return 0;
}


#define MG_SLIDERSIZE 20
#define MG_BARSIZE 3
#define MG_SLDRTIMESTEP 0.5
#define MGSLDRCOLOR_NORMAL D3DXCOLOR(0.4,0.6,1,1)
#define MGSLDRCOLOR_HOVER D3DXCOLOR(0.6,0.8,1,1)
const RECT MGRECT_SLIDERMARK = {96,236,116,256};
CMUTSlider::CMUTSlider(){
	Btn.SetColor(MGSLDRCOLOR_NORMAL);
	Bar.SetColor(MGCOLOR_GRAY);
	Bar.SetHeight(MG_BARSIZE);
	Btn.SetImgRect(MGRECT_SLIDERMARK);
	SetPos(0);
	SetTimeRecord(0.0f);
}
void CMUTSlider::Render(LPDIRECT3DDEVICE9 pDevice){
	D3DXCOLOR color ;
	float fLerp = MUTState()->GetElapsedTime()*MGCOLOR_CHANGERATE;
	if (Bar.GetPressed()||Btn.GetPressed()||Bar.GetHover()||Btn.GetHover()){
		D3DXColorLerp(&color,&Btn.GetColor(),&MGSLDRCOLOR_HOVER,fLerp);
		Btn.SetColor(color);
	}else{
		D3DXColorLerp(&color,&Btn.GetColor(),&MGSLDRCOLOR_NORMAL,fLerp);
		Btn.SetColor(color);
	}

	Bar.Setx(Getx());
	Bar.Sety(Gety()+(Btn.GetHeight()-Bar.GetHeight())/2);
	Bar.SetWidth(Width);
	Bar.SetAlpha(GetAlpha());
	MUTGUIDrawRect(pDevice,
		Bar.Getx(),Bar.Gety(),
		Width,Bar.GetHeight(),
		Bar.GetColorMulAlpha(),NULL,TRUE,-1,-1,2,2);

	Btn.Setx(Getx()+Pos-Btn.GetWidth()/2);
	Btn.Sety(Gety());
	Btn.SetWidth(MG_SLIDERSIZE);
	Btn.SetHeight(MG_SLIDERSIZE);
	Btn.SetAlpha(GetAlpha());
	MUTGUIDrawRect(pDevice,
		Btn.Getx(),Btn.Gety(),
		MG_SLIDERSIZE,MG_SLIDERSIZE,
		Btn.GetColorMulAlpha(),&Btn.GetImgRect(),TRUE,-1,-1,2,2);

	if ((!Btn.GetPressed())&&Bar.GetPressed()&&Bar.GetHover()){
		float fRecord = GetTimeRecord();
		fRecord += MUTState()->GetElapsedTime();
		POINT pt = GetPointRecord();
		if (fRecord>MG_SLDRTIMESTEP){
			int step = fRecord/MG_SLDRTIMESTEP;
			fRecord -= step*MG_SLDRTIMESTEP;

			int dx = pt.x-Getx()-GetPos();
			SetPos(GetPos()+dx);
			CheckPos();
		}
		SetTimeRecord(fRecord);
	}
}
bool CMUTSlider::OnMouseMessage(POINT pt, UINT uMsg, WPARAM wParam, LPARAM lParam){
	Btn.OnMouseMessage(pt,uMsg,wParam,lParam);
	Bar.OnMouseMessage(pt,uMsg,wParam,lParam);
	switch (uMsg){
	case WM_MOUSEMOVE:
		if (Btn.GetPressed()){//Drag
			POINT prept = MUTState()->GetPreMousePos();
			int dx = pt.x-prept.x;
			if ((dx<0&&pt.x<Getx()+GetPos())||
				(dx>0&&pt.x>Getx()+GetPos()))
				SetPos(GetPos()+dx);
			CheckPos();
		}
		break;
	}
	if(!Btn.GetHover()&&Bar.GetHover()){
		switch (uMsg){
		case WM_LBUTTONDOWN:
		case WM_LBUTTONDBLCLK:
			{
				int dx = pt.x-Btn.Getx();
				if (dx){
					dx = dx/abs(dx);
					SetPos(GetPos()+dx);
					CheckPos();
					SetPointRecord(pt);
					SetTimeRecord(0.0f);
				}
			}
			break;
		case WM_LBUTTONUP:
			SetTimeRecord(0.0f);
			break;
		}
	}
	return false;
}
int CMUTSlider::HandleMessage(UINT Msg,WPARAM wParam,LPARAM lParam){
	return 0;
}


#define MG_EDITBOXSIZE 20
#define MG_EDITBOXPADDING 2
#define MG_EDITCARETSIZE 2
#define MGEB_BLINKTIME 0.5
#define MGEDITCOLOR_SELECTTEXT MGCOLOR_WHITE
#define MGEDITCOLOR_SELECTBKG D3DXCOLOR(0,0,0.8,1)
CMUTEditBox::CMUTEditBox(){
	SetUpDownX(-1);
	SetCaretPos(0);
	ResetCaret();
	SetAnalyse(false);
	SetPressed(false);
	SetShowScroll(false);
	SetColor(MGCOLOR_WHITE);
	SetStartLine(0);
	SetShowLine(0);
	SetCaretInShowLine(false);
	enters.clear();
	str.push_back(0);
	ssa = NULL;
}
void CMUTEditBox::Render(LPDIRECT3DDEVICE9 pDevice){

	MUTGUIDrawRect(pDevice,
		x,y,
		Width,Height,
		GetColorMulAlpha(),NULL,TRUE,-1,-1,2,2);

	if (g_pFocusControl==this){
		float fTime = GetTimeRecord()+MUTState()->GetElapsedTime();
		if (fTime > MGEB_BLINKTIME){
			fTime = 0.0f;
			SetShowCaret( !GetShowCaret() );
		}
		SetTimeRecord(fTime);
	}

	if (!GetAnalyse()){
		AnalyseString();
		SetAnalyse(true);
	}
	
	bool bCaretShow = false;
	int iCaretx=x, iCarety=y;
	int i = 0, xText = x, yText = y, iStep = MG_EDITBOXSIZE - MG_EDITBOXPADDING;

	ShowLine = Height / iStep;
	if (ShowLine<linechar.size()){
		if (!GetShowScroll()){
			SetShowScroll(true);
			AnalyseString();
		}
	}else{
		SetShowScroll(false);
		ShowLine = linechar.size();
	}
	if (StartLine + ShowLine >= linechar.size()){
		StartLine = linechar.size() - ShowLine;
		if (StartLine < 0){
			StartLine = 0;
			ShowLine = linechar.size();
		}
	}
	if (GetCaretInShowLine()){
		//find first elem>caretpos
		auto elem = upper_bound(linechar.begin(), linechar.end(), CaretPos);
		int atLine = elem - linechar.begin() - 1;
		if (atLine<StartLine){
			StartLine = atLine;
		}else if(atLine>=StartLine+ShowLine){
			StartLine = atLine - ShowLine + 1;
		}
		SetCaretInShowLine(false);
		scroll.SetRangePos(StartLine);
	}
	int iCaretStart = min(CaretPosStart, CaretPosEnd);
	int iCaretEnd = max(CaretPosStart, CaretPosEnd);
	//for (auto itr = linechar.begin(); itr != linechar.end(); itr++)
	for (int i=StartLine; i<StartLine+ShowLine; i++){
		WCHAR tmp = 0;
		int lineStart = linechar[i];//*itr;
		int lineEnd = 0;
		//[lineStart, lineEnd)
		if (i+1 != linechar.size())
			lineEnd = linechar[i+1];
		else 
			lineEnd = str.size()-1;
		if (CaretPos >= lineStart && CaretPos <= lineEnd){
			iCarety = yText;
			iCaretx = x + CPtoX(CaretPos) - CPtoX(lineStart);
			bCaretShow = true;
		}
		if (lineEnd<str.size()){
			tmp = str[lineEnd];
			str[lineEnd] = 0;
		}

		MUTGUIDrawText(
			(LPWSTR)&(*str.begin())+lineStart,
			xText+MG_EDITBOXPADDING,yText+MG_EDITBOXPADDING,
			Width-2*MG_EDITBOXPADDING,Height-2*MG_EDITBOXPADDING,
			DT_LEFT|DT_SINGLELINE,MGCOLOR_BLACK);
		
		if ( !(lineStart>=iCaretEnd || lineEnd<=iCaretStart) ){
			int iSelStart = max(lineStart, iCaretStart);
			int iSelEnd = min(lineEnd, iCaretEnd);
			int startx = CPtoX(lineStart);
			int calstartx = CPtoX(iSelStart)-startx;
			int calendx = CPtoX(iSelEnd)-startx;
			int sx = xText+MG_EDITBOXPADDING+calstartx;
			int sy = yText+MG_EDITBOXPADDING;
			int swidth = calendx-calstartx;
			int sheight = MG_EDITBOXSIZE-2*MG_EDITBOXPADDING;
			MUTGUIDrawRect(pDevice,
				sx,sy,swidth,sheight,MGEDITCOLOR_SELECTBKG);
			MUTGUIDrawText(
				(LPWSTR)&(*str.begin())+iSelStart,
				sx,sy,
				swidth,sheight,
				DT_LEFT|DT_SINGLELINE,MGEDITCOLOR_SELECTTEXT);
		}
		yText += iStep;
		if (lineEnd<str.size())
			str[lineEnd] = tmp;
	}

	if (bCaretShow&&GetShowCaret()&&g_pFocusControl==this){
		//Show caret only when it's on focus
		D3DXCOLOR caretcolor = MGCOLOR_BLACK;
		caretcolor.a *= GetAlpha();
		MUTGUIDrawRect(pDevice,
			iCaretx+MG_EDITBOXPADDING,iCarety+MG_EDITBOXPADDING,
			MG_EDITCARETSIZE,MG_EDITBOXSIZE-2*MG_EDITBOXPADDING,
			caretcolor);
	}

	scroll.Setx(x+Width-MG_SCROLLBARSIZE);
	scroll.Sety(y);
	scroll.SetHeight(Height);
	scroll.SetWidth(MG_SCROLLBARSIZE);
	if (GetShowScroll()){
		scroll.SetAlpha(GetAlpha());
		scroll.SetRange(linechar.size()-ShowLine);
		StartLine = scroll.GetRangePos();
		scroll.Render(pDevice);
	}
}
void CMUTEditBox::AnalyseString(){
	if (ssa){
		ScriptStringFree(&ssa);
	}
	ScriptStringAnalyse(g_pFont->GetDC(),
		(LPWSTR)&(*str.begin()),
		str.size(),
		str.size()*3/2+16,
		-1,
		SSA_BREAK | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK,
		0,
		0,
		0,
		NULL,
		NULL,
		NULL,
		&ssa);
	strx.clear();
	linechar.clear();
	int xtmp = 0;
	for (int i=0; i<str.size(); i++){
		ScriptStringCPtoX(ssa,i,FALSE,&xtmp);
		strx.push_back(xtmp);
	}
	int LineWidth = Width - 2*MG_EDITBOXPADDING;
	if (GetShowScroll())
		LineWidth -= MG_SCROLLBARSIZE;
	if (LineWidth<0) return;

	int lineStart = 0;
	int lineEnd = 0;
	auto curitr = strx.begin(); 
	auto enteritr = enters.begin();
	while (true){
		//Find first elem > LineWidth
		auto elem = upper_bound(strx.begin()+lineStart, strx.end(), LineWidth);
		if (elem == strx.end()){
			lineEnd = strx.size();
		}else if (elem != strx.begin()){
			lineEnd = elem-strx.begin()-1;
		}

		if (enteritr != enters.end()){
			if (*enteritr >= lineStart && *enteritr < lineEnd){
				lineEnd = *enteritr+1;
				enteritr++;
			}
		}

		linechar.push_back(lineStart);
		if (lineEnd==strx.size())
			break;
		LineWidth = Width - 2*MG_EDITBOXPADDING + strx[lineEnd];
		if (GetShowScroll())
			LineWidth -= MG_SCROLLBARSIZE;
		lineStart = lineEnd;
	}
}
int CMUTEditBox::CPtoX(int cp){
	if (GetAnalyse())
		return strx[cp];
	else 
		return 0;
	/*
	int x = 0;
	ScriptStringCPtoX(ssa,cp,FALSE,&x);
	return x;*/
}
int CMUTEditBox::XtoCP(int x){
	int cp = 0;
	int Trail = 0;
	ScriptStringXtoCP(ssa,x,&cp,&Trail);
	if (cp<0){
		cp = 0;
	}else if (cp>=str.size()){
		cp = str.size()-1;
	}else if ( Trail && cp<str.size()-2){
		cp++;
	}
	return cp;
}
int CMUTEditBox::Point2CP(POINT pt,BOOL CheckShow){
	int iStep = MG_EDITBOXSIZE - MG_EDITBOXPADDING;
	int curline = (pt.y - y)/iStep;
	if (CheckShow){
		if (curline<0)
			curline = 0;
		else if (curline>=ShowLine)
			curline = ShowLine-1;
	}else{
		if (pt.y-y<0)
			curline--;
		if (curline<-StartLine)
			curline = -StartLine;
		else if(curline+StartLine>=linechar.size())
			curline = linechar.size()-StartLine-1;
	}
	curline += StartLine;
	int iStartChar = linechar[curline];
	int iEndChar = str.size()-1;
	if (curline+1 < linechar.size())
		iEndChar = linechar[curline+1]-1;
	int iFinalCP = XtoCP( pt.x - x - MG_EDITBOXPADDING + CPtoX(iStartChar) );
	if (iFinalCP>iEndChar)
		iFinalCP = iEndChar;
	if (iFinalCP<iStartChar)
		iFinalCP = iStartChar;
	return iFinalCP;
}
void CMUTEditBox::ResetCaret(){
	SetShowCaret(true);
	SetTimeRecord(0);
	SetCaretPosStart( GetCaretPos() );
	SetCaretPosEnd( GetCaretPos() );
}
int CMUTEditBox::MoveCaretUp(int bias){
	if (bias<0) 
		return MoveCaretDown(-bias);

	auto elem = upper_bound(linechar.begin(), linechar.end(), CaretPos);
	elem--;
	if (UpDownX<0)
		UpDownX = CPtoX(CaretPos) - CPtoX(*elem);

	int retPos = CaretPos;
	if (elem!=linechar.begin()){
		if (elem - linechar.begin() >= bias)
			elem -= bias;
		else
			elem = linechar.begin();

		retPos = XtoCP( CPtoX(*elem) + UpDownX );
		if (elem+1 != linechar.end() && retPos>=*(elem+1))
			retPos = *(elem+1)-1;
	}
	return retPos;
}
int CMUTEditBox::MoveCaretDown(int bias){
	if (bias<0)
		return MoveCaretUp(-bias);
	
	auto elem = upper_bound(linechar.begin(), linechar.end(), CaretPos);
	if (UpDownX<0)
		UpDownX = CPtoX(CaretPos) - CPtoX(*(elem-1));

	int retPos = CaretPos;
	if (elem != linechar.end()){
		bias--;
		if (linechar.end() - elem > bias)
			elem += bias;
		else
			elem = linechar.end()-1;

		retPos = XtoCP( CPtoX(*elem) + UpDownX );
		if (elem+1 != linechar.end() && retPos>=*(elem+1))
			retPos = *(elem+1)-1;
		else if (retPos>=str.size())
			retPos = str.size()-1;
	}
	return retPos;
}
int CMUTEditBox::MoveCaretLeft(int bias){
	if (bias<0) 
		return MoveCaretRight(-bias);
	int retPos = CaretPos - bias;
	if (retPos<0) retPos = 0;
	return retPos;
}
int CMUTEditBox::MoveCaretRight(int bias){
	if (bias<0) 
		return MoveCaretLeft(-bias);
	int retPos = CaretPos+bias;
	if (retPos>=str.size()) retPos=str.size()-1;
	return retPos;
}
void CMUTEditBox::RemoveSelection(){
	CaretPos = min(CaretPosStart,CaretPosEnd);
	int iStart = min(CaretPosStart,CaretPosEnd);
	int iEnd = max(CaretPosStart,CaretPosEnd);
	if (iStart<iEnd){
		str.erase(str.begin()+iStart,str.begin()+iEnd);
		//find elem1 >= iStart
		auto elem1 = lower_bound(enters.begin(), enters.end(), iStart);
		//find elem2 > iEnd
		auto elem2 = upper_bound(enters.begin(), enters.end(), iEnd);
		//position of enters after elem2 should be decreased
		auto after = elem2;
		int delnum = iEnd - iStart;
		while (after != enters.end())
			(*after++)-=delnum;
		//erase [elem1, elem2)
		enters.erase(elem1,elem2);
	}
	ResetCaret();
	SetAnalyse(false);
}
void CMUTEditBox::CopyToClipboard(){
	if ( OpenClipboard(MUTState()->Gethwnd()) ){
		//Succeed to open the clipboard
		EmptyClipboard();
		HGLOBAL hGlob = 0;
		if (CaretPosStart != CaretPosEnd){
			int CaretStart = min( CaretPosStart, CaretPosEnd );
			int CaretEnd = max( CaretPosStart, CaretPosEnd );
			int CopyLength = CaretEnd-CaretStart+1;
			hGlob = GlobalAlloc(GMEM_MOVEABLE, CopyLength*sizeof(WCHAR));
			WCHAR* gstr = (WCHAR*)GlobalLock(hGlob);
			CopyMemory(gstr, &(*(str.begin()+CaretStart)), (CaretEnd-CaretStart)*sizeof(WCHAR));
			gstr[CopyLength-1] = 0;
			GlobalUnlock(hGlob);
			SetClipboardData(CF_UNICODETEXT, hGlob);
		}
		CloseClipboard();
		/* The clipboard is now responsible to GlobalFree the data, not ourselves.
		if (hGlob)
			GlobalFree(hGlob);*/
		return;
	}
	MUTWinErrorTrace(GetLastError());
}
void CMUTEditBox::PasteFromClipboard(){
	RemoveSelection();
	if ( OpenClipboard(MUTState()->Gethwnd()) ){
		HANDLE hClipData = GetClipboardData(CF_UNICODETEXT);
		if (hClipData){
			WCHAR* ClipStr = (WCHAR*)GlobalLock(hClipData);
			if (ClipStr){
				InsertString(CaretPos, ClipStr);
				GlobalUnlock(hClipData);
			}
		}
		CloseClipboard();
	}
}
void CMUTEditBox::InsertString(int Start, WCHAR* pstr){
	int lenStr = lstrlen(pstr);
	str.insert(str.begin()+Start, pstr, pstr+lenStr);
	auto entersAfter = lower_bound( enters.begin(), enters.end(), Start);
	while (entersAfter != enters.end())
		(*entersAfter++)+=lenStr;
	for (int i=0; i<lenStr; i++){
		if (pstr[i] == VK_RETURN){
			enters.push_back(Start+i);
		}
	}
	sort(enters.begin(), enters.end());
	CaretPos = CaretPos + lenStr;
	SetAnalyse(false);
	ResetCaret();
}
bool CMUTEditBox::OnMouseMessage(POINT pt, UINT uMsg, WPARAM wParam, LPARAM lParam){
	if (GetShowScroll()){
		scroll.OnMouseMessage(pt,uMsg,wParam,lParam);
		if (uMsg == WM_MOUSEWHEEL){
			scroll.Scroll(GET_WHEEL_DELTA_WPARAM(wParam)/WHEEL_DELTA);
			return true;
		}
	}
	switch (uMsg){
	case WM_LBUTTONUP:
		SetPressed(false);
		break;
	case WM_MOUSEMOVE:
		if (!(MK_LBUTTON&wParam))
			SetPressed(false);
		if (GetPressed()){
			CaretPosEnd = Point2CP(pt,FALSE);
			SetCaretPos(CaretPosEnd);
			SetCaretInShowLine(true);
		}
		break;
	}
	if (!scroll.InRect(pt)&&InRect(pt)){
		switch (uMsg){
		case WM_LBUTTONDOWN:
			{
				SetCaretPos(Point2CP(pt));
				ResetCaret();
				SetUpDownX(-1);
				SetPressed(true);
			}
			break;
		}
	}
	return false;
}
bool CMUTEditBox::OnKeyboardMessage(UINT uMsg, WPARAM wParam, LPARAM lParam){
	switch (uMsg){
	case WM_KEYDOWN:
		//moving position of caret
		switch (wParam){
		case VK_UP:
			{	
				CaretPos = MoveCaretUp(1);
				ResetCaret();
				SetCaretInShowLine(true);
			}
			break;
		case VK_DOWN:
			{	
				CaretPos = MoveCaretDown(1);
				ResetCaret();
				SetCaretInShowLine(true);
			}
			break;
		case VK_LEFT:
			CaretPos = MoveCaretLeft(1);
			if (GetKeyState(VK_SHIFT)&0xFF00){
				CaretPosEnd = CaretPos;
			}else
				ResetCaret();
			SetCaretInShowLine(true);
			SetUpDownX(-1);
			break;
		case VK_RIGHT:
			CaretPos = MoveCaretRight(1);
			if (GetKeyState(VK_SHIFT)&0xFF00){
				CaretPosEnd = CaretPos;
			}else
				ResetCaret();
			SetCaretInShowLine(true);
			SetUpDownX(-1);
			break;
		case VK_HOME:
			{	//find first elem>CaretPos
				auto elem = upper_bound(linechar.begin(), linechar.end(), CaretPos);
				elem--;
				CaretPos = (*elem);
				ResetCaret();
				SetCaretInShowLine(true);
			}
			break;
		case VK_END:
			{
				//find first elem>CaretPos
				auto elem = upper_bound(linechar.begin(), linechar.end(), CaretPos);
				if (elem!=linechar.end())
					CaretPos = *elem-1;
				else
					CaretPos = str.size()-1; 
				ResetCaret();
				SetCaretInShowLine(true);
			}
			break;
		}

		break;
	case WM_CHAR:
		//Readonly or editable
		SetUpDownX(-1);
		switch (wParam){
		case VK_CANCEL: // ctrl-c
			CopyToClipboard();
			break;
		}

		if ( !(Style & ES_READONLY) ){
			//Eidtable
			SetCaretInShowLine(true);
			switch (wParam){
			case VK_BACK:
				if (GetCaretPosStart()!=GetCaretPosEnd()){
					//If there's a selection
					RemoveSelection();
				}else if (GetCaretPos()>0){
					/*
					if (CaretPos>=str.size()-1){
						str[CaretPos-1]=0;
					}
					str.erase(str.begin()+CaretPos-1);*/
					CaretPosStart = CaretPos-1;
					SetCaretPos(CaretPos-1);
					RemoveSelection();
				}
				break;
			case VK_CANCEL:
				break;
			case 22: // ctrl-v
				PasteFromClipboard();
				break;
			case VK_RETURN:
				
			default:
				if (GetCaretPosStart()!=GetCaretPosEnd()){
					RemoveSelection();
				}
				if (Style & ES_MULTILINE){//multiline
					//find the first elem>=caretpos
					auto itr = lower_bound(enters.begin(), enters.end(), CaretPos);
					if (itr != enters.end()){
						//all ENTER char after the new char position+1
						auto after = itr;
						while (after!=enters.end())
							(*after++)++;
					}
					if (wParam == VK_RETURN)
						//insert if it's an ENTER
						enters.insert(itr,CaretPos);
				}
				str.insert(str.begin()+GetCaretPos(),wParam);
				SetCaretPos(GetCaretPos()+1);
				SetAnalyse(false);
				ResetCaret();
				break;
			}
		}
		break;
	}
	return false;
}

list<MUTHWND> g_listDialog;

LRESULT MUTGUIWndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam){
	POINT pt = MUTState()->GetMousePos();

	if (message==WM_LBUTTONDOWN){
		if (!g_pFocusDialog||!g_pFocusDialog->InRect(pt)){
			for (auto itr = g_listDialog.begin();
				itr != g_listDialog.end(); itr++){
					CMUTDialog* pDialog = (CMUTDialog*)(*itr);
					if (pDialog->InRect(pt))
						g_pFocusDialog = pDialog;
			}
			g_pFocusControl = NULL;
		}
	}
	if (g_pFocusDialog){
		g_pFocusDialog->OnMsgProc(message,wParam,lParam);
	}/*else{
		for (auto itr = g_listDialog.begin();
				itr != g_listDialog.end(); itr++){
			CMUTDialog* pDialog = (CMUTDialog*)(*itr);
			pDialog->OnMsgProc(message,wParam,lParam);
		}
	}*/
	return 0;
}
bool CMUTDialog::OnMsgProc(UINT uMsg, WPARAM wParam, LPARAM lParam){
	POINT pt;
	switch (uMsg){
	case WM_MOUSEWHEEL:
	case WM_MOUSEMOVE:
	case WM_LBUTTONDOWN:
	case WM_LBUTTONDBLCLK:
	case WM_RBUTTONDOWN:
	case WM_LBUTTONUP:
	case WM_RBUTTONUP:
		pt.x = LOWORD(lParam);
		pt.y = HIWORD(lParam);

		if (uMsg == WM_MOUSEWHEEL)
			ScreenToClient(MUTState()->Gethwnd(),&pt);

		if (GetCaption()){
			Btncaption.OnMouseMessage(pt,uMsg,wParam,lParam);
			if (Btncaption.GetPressed()&&uMsg==WM_MOUSEMOVE){
				POINT prept = MUTState()->GetPreMousePos();
				int dx = pt.x-prept.x;
				int dy = pt.y-prept.y;
				Setx(x+dx);
				Sety(y+dy);
				for (auto itr = subcontrols.begin();
					itr != subcontrols.end(); itr++){
						CMUTControl* pControl = (CMUTControl*)(*itr);
						pControl->Setx(pControl->Getx()+dx);
						pControl->Sety(pControl->Gety()+dy);
				}
			}
		}

		if (!g_pFocusControl||!g_pFocusControl->OnMouseMessage(pt,uMsg,wParam,lParam)){
			CMUTControl* pFocusControl = NULL;
			for (auto itr = subcontrols.begin();
				itr != subcontrols.end(); itr++){
					CMUTControl* pControl = (CMUTControl*)(*itr);
					if (!pControl->GetVisible()) continue;
					if (pControl->InRect(pt)&&WM_LBUTTONDOWN==uMsg){
						pFocusControl = pControl;
					}
					if (pControl==g_pFocusControl) continue;
					pControl->OnMouseMessage(pt,uMsg,wParam,lParam);
			}
			if (uMsg==WM_LBUTTONDOWN){
				g_pFocusControl = pFocusControl;
			}
		}
		break;
	case WM_KEYDOWN:
	case WM_CHAR:
		if (g_pFocusControl)
			g_pFocusControl->OnKeyboardMessage(uMsg,wParam,lParam);
		/*
		for (auto itr = subcontrols.begin();
			itr != subcontrols.end(); itr++){
				CMUTControl* pControl = (CMUTControl*)(*itr);
				pControl->OnKeyboardMessage(uMsg,wParam,lParam);
		}*/
		break;
	}
	return false;
}

MUTHWND MUTGUICreateDialogModeless(int x,int y,int width,int height,bool bCaption,MUTDLGPROC DlgProc){
	MUTHWND hDlg = 0;
	//create a dialog ... 
	CMUTDialog* pDialog = new CMUTDialog;
	if (!pDialog) return 0;

	pDialog->Setx(x);
	pDialog->Sety(y);
	pDialog->SetWidth(width);
	pDialog->SetHeight(height);
	pDialog->SetCaption(bCaption);
	pDialog->SetDlgProc(DlgProc);

	hDlg = (MUTHWND)pDialog;
	g_listDialog.push_back(hDlg);
	if (DlgProc)
		(*DlgProc)(hDlg,WM_INITDIALOG,0,0);
	g_pFocusDialog = pDialog;
	return hDlg;
}

void MUTGUIEndDialog(MUTHWND hDlg){
	auto itr = find(g_listDialog.begin(), g_listDialog.end(), hDlg);
	if (g_listDialog.end() != itr)
		g_listDialog.erase(itr);
	CMUTDialog* pDialog = (CMUTDialog*)hDlg;
	pDialog->OnRelease();
	delete pDialog;
}

MUTHWND MUTGUICreateControl(MUTHWND hParent, MUTCTRL_TYPE type, DWORD style, int x, int y, int width, int height, DWORD id, LPWSTR title/*=0*/, DWORD group/*=0*/){
	if (!hParent) return 0;
	CMUTControl* pControl = NULL;
	CMUTDialog* pDialog = (CMUTDialog*)hParent;
	switch (type){
	case MUTCTRL_STATIC:
		{
			CMUTStatic* pState = new CMUTStatic;
			if (!pState) return 0;
			pControl = pState;
			break;
		}
	case MUTCTRL_BUTTON:
		{
			CMUTButton* pButton = new CMUTButton;
			if (!pButton) return 0;
			pControl = pButton;
			break;
		}
	case MUTCTRL_CHECKBOX:
		{
			CMUTCheckBox* pCheck = new CMUTCheckBox;
			if (!pCheck) return 0;
			pControl = pCheck;
			break;
		}
		break;
	case MUTCTRL_RADIOBUTTON:
		{
			CMUTRadioButton* pRadio = new CMUTRadioButton;
			if (!pRadio) return 0;
			pControl = pRadio;
			break;
		}
		break;
	case MUTCTRL_LISTBOX:
		{
			CMUTListBox* pList = new CMUTListBox;
			if (!pList) return 0;
			pControl = pList;
			break;
		}
		break;
	case MUTCTRL_COMBOBOX:
		{
			CMUTComboBox* pCombo = new CMUTComboBox;
			if (!pCombo) return 0;
			pControl = pCombo;
			break;
		}
	case MUTCTRL_SLIDER:
		{
			CMUTSlider* pSlider = new CMUTSlider;
			if (!pSlider) return 0;
			pControl = pSlider;
			break;
		}
	case MUTCTRL_EDITBOX:
		{
			CMUTEditBox* pEdit = new CMUTEditBox;
			if (!pEdit) return 0;
			pControl = pEdit;
			break;
		}
	}
	pControl->SetStyle(style);
	pControl->Setx(x);
	pControl->Sety(y);
	pControl->SetWidth(width);
	pControl->SetHeight(height);
	pControl->SetID(id);
	if (title)
		pControl->SetText(title);
	pControl->SetCtrlType(type);
	pControl->SetParentDialog(pDialog);
	MUTHWND hCtrl = (MUTHWND)pControl;
	pDialog->subcontrols.push_back(hCtrl);
	return hCtrl;
}

void MUTGenClear(D3DLOCKED_RECT& lrt, RECT rt, D3DXCOLOR color){
	for (int i = rt.top; i<rt.bottom; i++){
		for (int j = rt.left; j<rt.right; j++){
			LPDWORD pColor = (LPDWORD)((LPBYTE)lrt.pBits+i*lrt.Pitch)+j;
			*pColor = color;
		}
	}
}
void MUTGenUncheckedBox(D3DLOCKED_RECT& lrt, RECT rt){
	int d = 0;
	while (d<2){
		for (int i = rt.top+d; i<rt.bottom-d; i++){
			for (int j = rt.left+d; j<rt.right-d; j++){
				LPDWORD pColor = (LPDWORD)((LPBYTE)lrt.pBits+i*lrt.Pitch)+j;
				if (i==rt.top+d||i==rt.bottom-1-d||j==rt.left+d||j==rt.right-1-d){
					*pColor = D3DCOLOR_ARGB(255,50,50,50);
				}else{
					*pColor = D3DCOLOR_ARGB(0,0,0,0);
				}
			}
		}
		d++;
	}
}
void MUTGenCheckMark(D3DLOCKED_RECT& lrt, RECT rt){
	float k = float(rt.bottom-rt.top) / (rt.right-rt.left);
	int d = (rt.right-rt.left)/4;
	for (int i = rt.top+d; i<rt.bottom-d; i++){
		for (int j = rt.left+d; j<rt.right-d; j++){
			LPDWORD pColor = (LPDWORD)((LPBYTE)lrt.pBits+i*lrt.Pitch)+j;
			*pColor = D3DCOLOR_ARGB(255,0,0,255);
		}
	}
}
void MUTGenUncheckedRadio(D3DLOCKED_RECT& lrt, RECT rt){
	int r2 = (rt.right-rt.left)/2-1;
	r2 = r2*r2;
	int mx = (rt.right+rt.left)/2;
	int my = (rt.top+rt.bottom)/2;
	for (int i = rt.top; i<rt.bottom; i++){
		for (int j = rt.left; j<rt.right; j++){
			LPDWORD pColor = (LPDWORD)((LPBYTE)lrt.pBits+i*lrt.Pitch)+j;
			int d2 = (i-my)*(i-my)+(j-mx)*(j-mx);
			if(d2<r2-25){
				*pColor = D3DCOLOR_ARGB(0,0,0,0);
			}else if (d2<r2-9){
				*pColor = D3DCOLOR_ARGB(int((d2-r2+9)/16.0f*120),0,0,0);
			}else if (d2<r2+9){
				*pColor = D3DCOLOR_ARGB(255,0,0,0);
			}else if (d2<r2+25){
				*pColor = D3DCOLOR_ARGB(int((1.0f-(d2-r2-9)/16.0f)*120),0,0,0);
			}else{
				*pColor = D3DCOLOR_ARGB(0,0,0,0);
			}
		}
	}
}
void MUTGenRadioCircle(D3DLOCKED_RECT& lrt, RECT rt){
	int r2 = (rt.right-rt.left)/4;
	r2 = r2*r2;
	int mx = (rt.right+rt.left)/2;
	int my = (rt.top+rt.bottom)/2;
	for (int i = rt.top; i<rt.bottom; i++){
		for (int j = rt.left; j<rt.right; j++){
			LPDWORD pColor = (LPDWORD)((LPBYTE)lrt.pBits+i*lrt.Pitch)+j;
			int d2 = (i-my)*(i-my)+(j-mx)*(j-mx);
			if (d2<r2-9){
				*pColor = D3DCOLOR_ARGB(255,0,0,255);
			}else if (d2<r2){
				*pColor = D3DCOLOR_ARGB(200,0,0,255);
			}
		}
	}
}
void MUTGenTriangle(D3DLOCKED_RECT& lrt, RECT rt, int dir){
	int pad = (rt.bottom-rt.top)/3;
	int width = rt.right-rt.left-2*pad;
	int midx = (rt.right+rt.left)/2;
	int pady = (rt.bottom-rt.top-width)/2;
	if (dir>0) width=1;
	for (int i=rt.top+pady; i<rt.bottom-pady; i++){
		for (int j=midx-width/2; j<=midx+width/2; j++){
			LPDWORD pColor = (LPDWORD)((LPBYTE)lrt.pBits+i*lrt.Pitch)+j;
			*pColor = D3DCOLOR_ARGB(255,0,0,255);
		}
		width += dir;
	}
}
void MUTGenUpTriangle(D3DLOCKED_RECT& lrt, RECT rt){
	MUTGenTriangle(lrt,rt,1);
}
void MUTGenDownTriangle(D3DLOCKED_RECT& lrt, RECT rt){
	MUTGenTriangle(lrt,rt,-1);
}
void MUTGenButton(D3DLOCKED_RECT& lrt, RECT rt, D3DXCOLOR topcolor, D3DXCOLOR bottomcolor,bool bAddUp,bool bVertical){
	if (bVertical){
		swap(rt.left,rt.top);
		swap(rt.right,rt.bottom);
	}
	int r = (rt.bottom - rt.top)/2;
	int r2 = r*r;
	int eps = 9;

	for (int i=rt.top; i<rt.bottom; i++){
		D3DXCOLOR incolor,framecolor;
		D3DXColorLerp(&incolor,&topcolor,&bottomcolor,float(i-rt.top)/(rt.bottom-rt.top));
		framecolor = incolor;
		framecolor.a /=2;
		for (int j=rt.left; j<rt.right; j++){
			LPDWORD pColor = NULL;
			if (bVertical)
				pColor = (LPDWORD)((LPBYTE)lrt.pBits+j*lrt.Pitch)+i;
			else
				pColor = (LPDWORD)((LPBYTE)lrt.pBits+i*lrt.Pitch)+j;
			DWORD origin = *pColor;

			if (j-rt.left<=r){//left/top half-circle

				int d2 = (r-j+rt.left)*(r-j+rt.left)+(i-rt.top-r)*(i-rt.top-r);
				if (d2<r2-eps){
					*pColor = incolor;
				}else if(d2<r2+eps*2){
					*pColor = framecolor;
				}else{
					//*pColor = D3DCOLOR_ARGB(0,0,0,0);
				}
			}else if (rt.right-j>r){//mid rect
				if (i==rt.top||i==rt.bottom){
					*pColor = framecolor;
				}else{
					*pColor = incolor;
				}
			}else{//right half-circle
				int d2 = (r-rt.right+j)*(r-rt.right+j)+(i-rt.top-r)*(i-rt.top-r);
				if (d2<r2-eps){
					*pColor = incolor;
				}else if(d2<r2+eps*2){
					*pColor = framecolor;
				}else{
					//*pColor = D3DCOLOR_ARGB(0,0,0,0);
				}
			}
			if (bAddUp){
				D3DXCOLOR c1 = origin;
				D3DXCOLOR c2 = *pColor;
				D3DXCOLOR c = c1*(1-c2.a)+c2*c2.a;
				c.a = c1.a;
				*pColor = c;
			}
		}
	}
}
void MUTGenSliderMark(D3DLOCKED_RECT& lrt, RECT rt, D3DXCOLOR tcolor, D3DXCOLOR bcolor){
	int maxw = (rt.right-rt.left)*2/3;
	int midx = (rt.right+rt.left)/2;
	int width=1;
	for (int i=rt.bottom-1; i>=rt.top; i--){
		D3DXCOLOR color;
		D3DXColorLerp(&color,&tcolor,&bcolor,float(i-rt.top)/(rt.bottom-rt.top));
		for (int j=midx-width/2; j<=midx+width/2; j++){
			LPDWORD pColor = (LPDWORD)((LPBYTE)lrt.pBits+i*lrt.Pitch)+j;
			*pColor = color;
		}
		if (width<maxw)
			width++;
	}
}

HRESULT MUTGenerateUITexture(){
	D3DLOCKED_RECT lrt;
	g_pTexture->LockRect(0,&lrt,NULL,0);
	for (int i=0; i<256; i++){
		for (int j=0; j<256; j++){
			*(((LPDWORD)((LPBYTE)lrt.pBits+i*lrt.Pitch))+j) = D3DCOLOR_ARGB(255,255,255,255);
		}
	}

	
	//Unchecked
	MUTGenUncheckedBox(lrt,MGRECT_UNCHECKED);

	//Checked
	MUTGenUncheckedBox(lrt,MGRECT_CHECKED);
	MUTGenCheckMark(lrt,MGRECT_CHECKED);

	//UncheckedRadio
	MUTGenUncheckedRadio(lrt,MGRECT_RADIOUNCHECKED);

	//CheckedRadio
	MUTGenUncheckedRadio(lrt,MGRECT_RADIOCHECKED);
	MUTGenRadioCircle(lrt,MGRECT_RADIOCHECKED);

	//ComboBtn
	MUTGenUncheckedRadio(lrt,MGRECT_COMBOBTN);
	MUTGenDownTriangle(lrt,MGRECT_COMBOBTN);

	//Scroll btns
	MUTGenUpTriangle(lrt,MGRECT_SCROLLUP);
	MUTGenDownTriangle(lrt,MGRECT_SCROLLDOWN);

	//Button
	MUTGenClear(lrt,MGRECT_BUTTON,D3DXCOLOR(0,0,0,0));
	MUTGenButton(lrt,MGRECT_BUTTON,D3DXCOLOR(0.3,0.3,0.3,1),D3DXCOLOR(1,1,1,1),FALSE,FALSE);
	RECT rtBL = MGRECT_BUTTON;
	rtBL.left += 4;
	rtBL.right -= 4;
	rtBL.bottom = (rtBL.bottom+rtBL.top)/2;
	MUTGenButton(lrt,rtBL,D3DXCOLOR(0.8,0.8,0.8,1),D3DXCOLOR(0.6,0.6,0.6,1),TRUE,FALSE);

	//slider of Scrool bar
	MUTGenClear(lrt,MGRECT_SCROLLSLIDER,D3DXCOLOR(0,0,0,0));
	MUTGenButton(lrt,MGRECT_SCROLLSLIDER,D3DXCOLOR(1,1,1,1),D3DXCOLOR(0.7,0.7,0.7,1),FALSE,TRUE);
	rtBL = MGRECT_SCROLLSLIDER;
	rtBL.top += 4;
	rtBL.bottom -= 4;
	rtBL.left = (rtBL.left+rtBL.right)/2;
	MUTGenButton(lrt,rtBL,D3DXCOLOR(0.8,0.8,0.8,1),D3DXCOLOR(1,1,1,1),TRUE,TRUE);

	//mark of slider
	MUTGenClear(lrt,MGRECT_SLIDERMARK,D3DXCOLOR(0,0,0,0));
	MUTGenSliderMark(lrt,MGRECT_SLIDERMARK,D3DXCOLOR(1,1,1,1),D3DXCOLOR(0.7,0.7,0.7,1));
	g_pTexture->UnlockRect(0);
	return S_OK;
}

HRESULT MUTGUIOnCreateDevice(LPDIRECT3DDEVICE9 pDevice){
	HRESULT hr = S_OK;
	if (FAILED(hr = D3DXCreateSprite(pDevice,&g_pSprite))){
		MUTDXErrorTrace(hr, L"D3DXCreateSprite failed.");
	}
	HDC hdc = GetDC(MUTState()->Gethwnd());
	int dpi = GetDeviceCaps(hdc,LOGPIXELSY);
	int fh = -MulDiv(9, dpi, 72);
	if (FAILED(hr = D3DXCreateFont(pDevice,
		fh,0,FW_NORMAL,0,FALSE,CHINESEBIG5_CHARSET,OUT_DEVICE_PRECIS,
		CLEARTYPE_QUALITY,DEFAULT_PITCH|FF_DONTCARE,L"Tahoma",&g_pFont))){
		MUTDXErrorTrace(hr, L"D3DXCreateFont failed.");
	}
	if (FAILED(hr = D3DXCreateTexture(pDevice,
		256,256,1,0,D3DFMT_A8R8G8B8,D3DPOOL_MANAGED,&g_pTexture))){
		MUTDXErrorTrace(hr, L"D3DXCreateTexture failed.");
	}else{
		MUTGenerateUITexture();
	}                                       
	
	return S_OK; 
}

HRESULT MUTGUIOnResetDevice(LPDIRECT3DDEVICE9 pDevice){
	return S_OK;
}

HRESULT MUTGUIOnReleaseDevice(){
	for (auto itr = g_listDialog.begin();
		itr != g_listDialog.end(); itr++){
		CMUTDialog* pDialog = (CMUTDialog*)*itr;
		if (pDialog){
			pDialog->OnRelease();
			delete pDialog;
		}
	}
	if (g_pFont) g_pFont->Release();
	if (g_pSprite) g_pSprite->Release();
	if (g_pTexture) g_pTexture->Release();
	g_pFont = NULL;
	g_pSprite = NULL;
	g_pTexture = NULL;
	return S_OK;
}

HRESULT MUTGUIOnRender(LPDIRECT3DDEVICE9 pDevice){
	g_pSprite->Begin(D3DXSPRITE_ALPHABLEND);

	for (auto itr = g_listDialog.begin();
			itr != g_listDialog.end(); itr++){
		CMUTDialog* pDialog = (CMUTDialog*)(*itr);
		if (pDialog==g_pFocusDialog) continue;
		pDialog->Render(pDevice);
	}
	if (g_pFocusDialog)
		g_pFocusDialog->Render(pDevice);
	g_pSprite->End();
	return S_OK;
}